package scales.xml
import scala.collection.immutable.Map
import scala.collection.generic.CanBuildFrom
import scalaz._
import Scalaz._
import scales.utils.{EitherLike, LeftLike}
import scales.utils.collection.{ListSet, Tree}
import java.nio.charset.Charset
import scales.xml.impl.{FromParser, IsFromParser, NotFromParser, EqualsHelpers}
case class Attribute(name: AttributeQName, value: String)
object Attr {
def unapply(attr: Attribute) = Some(attr.value)
}
sealed trait XmlEvent
import ScalesXml._
import xml._
import scales.xml.impl.DefaultHashes._
sealed trait Elem extends XmlEvent {
val name : QName
def attributes : Attributes
def namespaces : Map[String, String] = emptyNamespaces
def copy(name: QName = name, attributes: Attributes = attributes, namespaces: Map[String, String] = namespaces)(implicit fromParser : FromParser) : Elem
override def equals( other : Any ) = other match {
case o : Elem =>
if ((name ==== o.name)
&& (attributes == o.attributes)
&& (namespaces == o.namespaces) )
true
else
false
case _ => false
}
override def hashCode() : Int = {
var hs = 1
hs = (hs * 31) + name.hashCode
hs = (hs * 31) + (
if (emptyAttributes eq attributes)
emptyAttributesHash
else
attributes.hashCode
)
hs = (hs * 31) + (
if (namespaces eq emptyNamespaces)
emptyNamespacesHash
else
namespaces.hashCode
)
hs
}
override def toString(): String = {
var sb = new java.lang.StringBuilder()
sb.append("Elem(").
append(name)
if (emptyAttributes ne attributes)
sb.append(", ").
append(attributes)
if (emptyNamespaces ne namespaces)
sb.append(", ").
append(namespaces)
sb.append(")").toString()
}
}
object Elem {
def apply(name : QName, attributes : Attributes, namespaces : Iterable[ PrefixedNamespace ] )(implicit fromParser : FromParser) : Elem =
apply(name, attributes, namespaces.map( p => p.prefix -> p.ns.uri ).toMap)(fromParser)
def apply(name : QName, namespaces : Iterable[ PrefixedNamespace ] )(implicit fromParser : FromParser) : Elem =
apply(name, emptyAttributes, namespaces.map( p => p.prefix -> p.ns.uri ).toMap)(fromParser)
def apply(name : QName , namespace : PrefixedNamespace, namespaces : PrefixedNamespace * )(implicit fromParser : FromParser) : Elem =
apply(name, emptyAttributes, (namespace +: namespaces).map( p => p.prefix -> p.ns.uri ).toMap)(fromParser)
def apply(name : QName, attributes : Attributes, namespace : PrefixedNamespace, namespaces : PrefixedNamespace * )(implicit fromParser : FromParser) : Elem =
apply(name, attributes, (namespace +: namespaces).map( p => p.prefix -> p.ns.uri ).toMap)(fromParser)
private[Elem] final class NoNamespacesElem( namei : QName, attributesi : Attributes ) extends Elem {
val name = namei
val attributes = attributesi
def copy(name: QName = name, attributes: Attributes = attributes, namespaces: Map[String, String] = namespaces)(implicit fromParseri : FromParser) : Elem =
apply(name, attributes, namespaces)(fromParseri)
}
private[Elem] final class QNameOnlyElem( namei : QName ) extends Elem {
val name = namei
def attributes = emptyAttributes
def copy(name: QName = name, attributes: Attributes = attributes, namespaces: Map[String, String] = namespaces)(implicit fromParseri : FromParser) : Elem =
apply(name, attributes, namespaces)(fromParseri)
}
private[Elem] final class FullElem(namei: QName, attributesi: Attributes, namespacesi: Map[String, String]) extends Elem {
val name = namei
val attributes = attributesi
override val namespaces = namespacesi
def copy(name: QName = name, attributes: Attributes = attributes, namespaces: Map[String, String] = namespaces)(implicit fromParseri : FromParser) : Elem =
apply(name, attributes, namespaces)(fromParseri)
}
private[Elem] final class NoAttribsElem(namei: QName, namespacesi: Map[String, String]) extends Elem {
val name = namei
def attributes = emptyAttributes
override val namespaces = namespacesi
def copy(name: QName = name, attributes: Attributes = attributes, namespaces: Map[String, String] = namespaces)(implicit fromParseri : FromParser) : Elem =
apply(name, attributes, namespaces)(fromParseri)
}
def apply(namei: QName, attributesi: Attributes = emptyAttributes, namespacesi: Map[String, String] = emptyNamespaces)(implicit fromParser : FromParser) : Elem = {
if (fromParser eq NotFromParser) {
require(!(namei.prefix.map { p =>
(p eq PrefixedNamespace.xmlPRE) ||
(p eq PrefixedNamespace.xmlnsPRE)
}.getOrElse(false)), "Prefixes (xmlns, xml) are not allowed for elements")
}
if (namespacesi.isEmpty)
if (!attributesi.isEmpty)
new NoNamespacesElem( namei, attributesi )
else
new QNameOnlyElem( namei )
else
if (!attributesi.isEmpty)
new FullElem( namei, attributesi, namespacesi )
else
new NoAttribsElem( namei, namespacesi )
}
def unapply( el : Elem) = Some((el.name, el.attributes, el.namespaces))
}
sealed trait XmlItem extends LeftLike[XmlItem, Tree[XmlItem, Elem, XCC]] with XmlEvent {
val value: String
override def hashCode() : Int =
value.hashCode
def doEquals( other : Any, clazz : Class[_] ) =
if (clazz.isInstance(other)) {
val o = other.asInstanceOf[XmlItem]
if (o eq this) true
else (o.value == value)
} else false
}
case class Text(value: String) extends XmlItem
trait extends XmlItem {
override def ( : Any ) = doEquals(other, Comment.commentClass)
}
object {
val = Comment("a")(IsFromParser).getClass
def ( : String)(implicit : FromParser) = new {
if (fromParser eq NotFromParser)
require(valuei.indexOf("--") == -1, "Comments cannot contain the sequence --")
val = valuei
}
def ( : Comment) = Some(cmt.value)
}
trait CData extends XmlItem {
override def equals( other : Any ) = doEquals(other, CData.cdataClass)
}
object CData {
val cdataClass = CData("")(IsFromParser).getClass
def apply(valuei : String)(implicit fromParser : FromParser) = new CData {
if (fromParser eq NotFromParser)
require(valuei.indexOf("]]>") == -1,
"CData sections cannot contain the sequence ]]>")
val value = valuei
}
def unapply(cmt : CData) = Some(cmt.value)
}
trait PI extends XmlItem {
override def equals( other : Any ) =
if (other.isInstanceOf[PI]) {
val o = other.asInstanceOf[PI]
(o.value == value) && (o.target == target)
} else false
override def hashCode() : Int = {
var hs = 1
hs = (hs * 31) + value.hashCode
hs = (hs * 31) + target.hashCode
hs
}
val target : String
}
object PI {
def apply(targeti : String, valuei : String)(implicit fromParser : FromParser) = new PI {
if (fromParser eq NotFromParser) {
require(valuei.indexOf("?>") == -1, "PI Processing Instructions cannot contain the sequence ?> in the value")
require(targeti.indexOf("?>") == -1, "PI Processing Instructions cannot contain the sequence ?> in the value")
require(!targeti.toLowerCase.startsWith("xml"), "PI Processing Instructions targets cannot start with ?>")
}
val value = valuei
val target = targeti
}
def unapply(pi : PI) = Some((pi.target, pi.value))
}
case class Declaration(version: XmlVersion = defaultVersion, encoding: Charset = scales.utils.defaultCharset, standalone: Boolean = false)
case class DTD(name: String, publicId: String, systemId: String)
case class Prolog(
decl: Declaration = Declaration(),
misc: Miscs = emptyMiscs,
dtd: Option[DTD] = None)
case class EndMisc(misc: Miscs = emptyMiscs)
trait DocLike {
def prolog: Prolog
def end: EndMisc
}
case class EmptyDoc(prolog: Prolog = Prolog(), end: EndMisc = EndMisc()) extends DocLike
case class Doc(rootElem: XmlTree, prolog: Prolog = Prolog(), end: EndMisc = EndMisc()) extends DocLike {
override def toString() = "scales.xml.doc"
}
case class EndElem(name: QName, namespaces: Map[String, String] = Map[String, String]())
object Attribs {
def apply( attribs : Attribute * ) : Attributes = {
import EqualsHelpers._
emptyAttributes ++ attribs
}
}